package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.feign.product.SkuInfoFeignClient;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.sf.jsqlparser.statement.select.KSQLWindow;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author dyqstart
 * @create 2021-08-17-19:20
 * @since 1.0.0
 */
@Component
public class CartServiceImpl implements CartService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    SkuInfoFeignClient skuInfoFeignClient;


    /**
     * 登录了带userId 和 TempId
     * 没登录 带 TempId
     *
     * @param request
     * @return
     */
    @Override
    public String determinCartKey(HttpServletRequest request) {
        //请求头中如果有userId，这就是当前的登录的用户id
        String userId = request.getHeader("userId");
        if (!StringUtils.isEmpty(userId)) {
            //说明用户登录，网关把id透传过来
            return RedisConst.CART_PREFIX + userId;
        } else {
            //说明用户没有登录，就用临时购物车
            String userTempId = request.getHeader("userTempId");
            return RedisConst.CART_TEMP_PREFIX + userTempId;

        }
    }

    /**
     * 给购物车保存数据
     *
     * @param key
     * @param skuId
     * @param skuNum
     * @return
     */
    @Override
    public CartInfo addToCart(String key, Long skuId, Integer skuNum) {

        CartInfo result = null;

        //拿到操作redis的容器
        BoundHashOperations<String, String, String> hashOps = getCart(key);

        //用户购物车和临时购物车过期时间是不一样的
        if (hashOps.hasKey(skuId.toString())) {
            //redis购物车已经有这个商品，商品数量叠加
            //1、现获取到这个商品信息
            String jsonStr = hashOps.get(skuId.toString());
            try {
                //从购物车获取到商品
                result = new ObjectMapper().readValue(jsonStr, CartInfo.class);

            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            Integer num = result.getSkuNum();

            //修改购物车数量
            result.setSkuNum(num + skuNum);

            //再次查询价格，或者叫更新价格
            result.setSkuPrice(skuInfoFeignClient.getSkuPrice(skuId));

            String string = null;
            try {
                string = new ObjectMapper().writeValueAsString(result);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            hashOps.put(skuId.toString(), string);

        } else {
            //给购物车保存cartInfo(SkuInfo) 信息
            //skuId,远程查询sku详情
            SkuInfo skuInfo = skuInfoFeignClient.getSkuInfo(skuId);

            //给redis中保存的加入到购物车的当前商品信息

            result = CartInfo.convertSkuInfoCart(skuInfo);

            //额外设置：调一个最新的价格
            BigDecimal skuPrice = skuInfoFeignClient.getSkuPrice(skuId);
            result.setSkuPrice(skuPrice);
            //设置数量
            result.setSkuNum(skuNum);

            String jsonStr = null;
            try {
                jsonStr = new ObjectMapper().writeValueAsString(result);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            hashOps.put(skuId.toString(), jsonStr);

            //添加过期时间
            if (key.startsWith("cart:temp")) {
                //判断此为临时购物车，需要添加过期时间
                redisTemplate.expire(key, RedisConst.TEMP_CART_EXPIRE, TimeUnit.SECONDS);
            }


        }
        return result;
    }


    @Override
    public String userCartKey(HttpServletRequest request) {
        String userId = request.getHeader("userId");
        if (!StringUtils.isEmpty(userId)) {
            return RedisConst.CART_PREFIX + userId;
        }
        return null;
    }

    @Override
    public String tempCartKey(HttpServletRequest request) {
        String userTempId = request.getHeader("userTempId");
        if (!StringUtils.isEmpty(userTempId)) {
            return RedisConst.CART_TEMP_PREFIX + userTempId;
        }
        return null;
    }

    @Override
    public List<CartInfo> listCart(String userKey, String userTempKey) {

        List<CartInfo> result = null;

        /**
         * 1、如果用户未登录默认 key:TempId临时
         * 2、如果用户登陆了，默认key:userId
         *      同时带TempId 如果TempId有值需要将商品合并到这个这个用户的真是购物车商品中
         */
        if (!StringUtils.isEmpty(userTempKey)) {
            BoundHashOperations<String, String, String> cart = getCart(userTempKey);
            if (cart.size() > 0) {
                //临时购物车有数据,则调用方法全部拿出来
                //合并方法
                result = getCartInfoList(userTempKey);

            }
        }

        if (!StringUtils.isEmpty(userKey)) {
            //说明用户登录了,把临时购物车的数据和用户购物车合并起来
            //其实就是把临时购物车的商品添加到用户购物车中，用户购物车本来就会有那么数量+1，没有就直接添加商品
            if (!CollectionUtils.isEmpty(result)) {
                //临时购物车中不为空
                //合并
                for (CartInfo info : result) {
                    //往userKey中存，所有商品id,所有商品数量
                    addToCart(userKey, info.getSkuId(), info.getSkuNum());
                    //合并完之后，要删除临时购物车
                    clearCart(userTempKey);
                }
            }
            //如果前面合并了，拿到的就是合并的，如果没合并，拿到的就是用户购物车的商品列表
            result = getCartInfoList(userKey);

        }

        return result;
    }


    /**
     * 获取购物车中所有商品
     */
    public BoundHashOperations<String, String, String> getCart(String key) {
        return redisTemplate.boundHashOps(key);
    }

    /**
     * 获取购物车的所有数据
     */
    public List<CartInfo> getCartInfoList(String key) {
        //准备一个集合用来存放所有的购物车
        ArrayList<CartInfo> cartInfos = new ArrayList<>();
        //拿到购物车
        BoundHashOperations<String, String, String> cart = getCart(key);
        //遍历出购物车中所有项商品
        List<String> values = cart.values();
        if (!CollectionUtils.isEmpty(values)) {
            //redis中这个购物车有数据
            for (String skuJson : values) {
                CartInfo cartInfo = null;
                try {
                    cartInfo = new ObjectMapper().readValue(skuJson, CartInfo.class);

                    //TODO 此处可以远程调用。再次获取商品价格
//                    CartInfo finalCartInfo = cartInfo;
//                    CompletableFuture.runAsync(()->{
//                        //线程没有更新购物车价格，也没事。
//                        BigDecimal skuPrice = skuInfoFeignClient.getSkuPrice(finalCartInfo.getSkuId());
//                        finalCartInfo.setSkuPrice(skuPrice);
//                        try {
//                            getCart(key).put(finalCartInfo.getSkuId().toString(),new ObjectMapper().writeValueAsString(finalCartInfo));
//                        } catch (JsonProcessingException e) {
//                        }
//                    });
//                    cartInfo.setCartPrice(); //当时存购物车的价格

                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }

                cartInfos.add(cartInfo);
            }
        }

        return cartInfos;
    }

    /**
     * 在用户登录以后，进行合并临时购物车，合并后，清空临时购物车
     * 需要调用此方法
     */
    @Override
    public void clearCart(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 购物车商品选中
     *
     * @param key
     * @param skuId
     * @param checked
     */
    @Override
    public void checkCartItem(String key, Long skuId, Integer checked) {
        ObjectMapper objectMapper = new ObjectMapper();

        BoundHashOperations<String, String, String> cart = getCart(key);
        //获取到购物车里的商品
        String json = cart.get(skuId.toString());

        //转成CartInfo对象
        CartInfo cartInfo = null;
        try {
            cartInfo = objectMapper.readValue(json, CartInfo.class);
            cartInfo.setCreateTime(null);
            cartInfo.setUpdateTime(null);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        //设置好状态
        cartInfo.setIsChecked(checked);

        //转回String
        String result = null;
        try {
            result = objectMapper.writeValueAsString(cartInfo);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        if (cart.size() <= 200) {
            cart.put(skuId.toString(), result);
        }else {
            throw new RuntimeException("购物车数量限制");
        }
    }

    @Override
    public void deleteCartItem(String key, Long skuId) {
        BoundHashOperations<String, String, String> cart = getCart(key);

        cart.delete(skuId.toString());
    }

    /**
     * 获取被选中的所有商品购物车的相信信息
     * @param key
     * @return
     */
    @Override
    public List<CartInfo> listCheckCartInfo(String key) {
        BoundHashOperations<String, String, String> cart = getCart(key);

        ObjectMapper objectMapper = new ObjectMapper();
        //准备存放所有被选中的商品
        ArrayList<CartInfo> checked = new ArrayList<>();

        //返回购物车中每个商品的json数据
        List<String> values = cart.values();
        if (!CollectionUtils.isEmpty(values)){
            for (String value : values) {

                CartInfo cartInfo = null;
                try {
                    cartInfo = objectMapper.readValue(value, CartInfo.class);
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }

                if (cartInfo.getIsChecked().intValue() == 1){
                    //被选中
                    checked.add(cartInfo);
                }
            }
        }

        return checked;
    }
}
